﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;

using Qiang.Data;
using Qiang.Topology.Geometries;
using Qiang.Styles;

using Point = System.Drawing.Point;
using SelectionMode = Qiang.Styles.SelectionMode;

namespace Qiang.Controls
{
    //此类绘制方法:在一张位图上绘制图层信息，然后map控件再绘制这张位图
    //当视图区域发生变化时就必须要发生重绘操做
    //引起视图区域发后变化的事件有 1 控件的大小变化 2 图层的放大缩小平移

    //map类：控制图层、

    [Serializable]
    public class Map : IMap
    {

        #region 初始化

        public Map()
        {
            this._viewExtent = new Extent(-180, -90, 180, 90); //这个范围指的是经纬度的范围
            this._bufferImage = this.CreateBufferImage();
            this.Layers = new MapLayerCollection();
        }


        public Map(MapControl controlMap, Extent viewExtent)
            : this()
        {
            this._control = controlMap;
            this.ViewExtent = viewExtent;

            this._bufferImage = this.CreateBufferImage();
        }

        public Map(MapControl controlMap)
            : this()
        {
            this._control = controlMap;
        }


        #endregion


        #region 字段

        private int _width;
        private int _height;

        //图层集合
        private MapLayerCollection _layers;

        //缓冲位图。将所有的图层信息绘制到此位图。再将此位图显示到map控件。
        private Image _bufferImage;

        private IExtent _viewExtent;

        [NonSerialized]
        private MapControl _control;

        private Rectangle _backView;

        private Rectangle _currentView;

        #endregion


        #region 属性


        /// <summary>
        /// 图层集合
        /// </summary>
        public MapLayerCollection Layers
        {
            get { return _layers; }
            set
            {
                if (_layers != null)
                {
                    //移除原始图层集合的事件
                    RemoveLayerEvents();
                }
                _layers = value;
                if (value != null)
                {
                    //订阅新图层集合的事件
                    HandleLayerEvents();
                }

            }
        }


        /// <summary>
        /// 缓冲位图。将所有的图层信息绘制到此位图。再将此位图显示到map控件。
        /// </summary>
        public Image BufferImage
        {
            get { return _bufferImage; }
            //set { _backImage = value; }
        }


        public MapControl Control
        {
            get { return _control; }
            set { _control = value; }
        }


        /// <summary>
        /// 
        /// </summary>
        public IExtent Extent
        {
            get
            {
                return this.GetLayersExtent();
            }
        }


        /// <summary>
        /// 这个指的是可视区域不变时起始、大小。针对图层
        /// </summary>
        public IExtent ViewExtent
        {
            get { return _viewExtent; }
            set
            {
                IExtent ext = value.Copy();

                this.ResetExtentRatio(ext);  //根据窗体重新设置Extent比例

                _viewExtent = ext;

                this.ResetBufferImage();  //重设位图大小，重绘图层
            }
        }


        /// <summary>
        /// 同上。针对控件
        /// </summary>
        public Rectangle View
        {
            get { return _backView; }
            set { _backView = value; }
        }



        /// <summary>
        /// 这个是指当视图区域变化时的临时视图区域。针对控件
        /// </summary>
        public Rectangle CurrentView
        {
            get { return _currentView; }
            set
            {
                _currentView = value;
            }
        }


        #endregion


        #region 方法

        /// <summary>
        /// 创建背景位图。所有的图层信息将在这个位图上绘制
        /// </summary>
        /// <returns></returns>
        private Bitmap CreateBufferImage()
        {
            if (this._control != null)
            {
                this._width = this._control.Width;
                this._height = this._control.Height;
            }
            else
            {
                this._width = 1000;
                this._height = 800;
            }

            this._backView = new Rectangle(0, 0, this._width, this._height);

            if (this._width < 5) this._width = 5;
            if (this._height < 5) this._height = 5;

            return new Bitmap(this._width, this._height);

        }


        public void DrawBackBitmap(PaintEventArgs e)
        {
            //这个方法是在map控件的OnPaint里调用，用以当视图区域变化时要显示的位图（图层信息）也要随着变化
            //比如放大时，视图区域变小，要绘制的区域也要变小。平移时，视图区域向左移，绘制区域也要向左移

            //不管临时视图区域是否正在变化，都绘制临时视图区域的信息。当前要绘制的区域

            Rectangle clipRect = e.ClipRectangle;
            if (clipRect.IsEmpty) clipRect = this._control.ClientRectangle;

            Rectangle currentRect = new Rectangle
                                   {
                                       X = this._currentView.X + (clipRect.X * this._currentView.Width) / this._control.ClientRectangle.Width,
                                       Y = this._currentView.Y + (clipRect.Y * this._currentView.Height) / this._control.ClientRectangle.Height,
                                       Width = clipRect.Width * this._currentView.Width / this._control.ClientRectangle.Width,
                                       Height = clipRect.Height * this._currentView.Height / this._control.ClientRectangle.Height
                                   };

            e.Graphics.DrawImage(this._bufferImage, clipRect, currentRect, GraphicsUnit.Pixel);

        }


        /// <summary>
        /// 绘制图层到位图上
        /// </summary>
        public void InitializeBackBitmap()
        {
            //这个方法是辅助绘制图层信息到一个位图上
            //map控件绘制显示这个位图就行了

            //if (this._width == 0 || this._height == 0) return;  //这一句判断好纠结啊，有没有必要呢？？？

            if (this._bufferImage == null) this.CreateBufferImage();

            Graphics g = Graphics.FromImage(this._bufferImage);

            Rectangle mapRectangle = new Rectangle(0, 0, this._width, this._height);

            MapDrawArgs args = new MapDrawArgs(g, mapRectangle, this.ViewExtent);

            g.Clip = new Region(mapRectangle);  //设置位图的绘图区域

            //设置位图背景颜色
            if (this._control != null)
            {
                g.Clear(this._control.BackColor);
            }
            else
            {
                g.Clear(Color.White);
            }

            //各个图层自己绘制
            foreach (IMapLayer layer in this.Layers)
            {
                if (layer.Visible)
                    layer.DrawRegion(args, this._viewExtent);
            }

            this._currentView = this._backView;

        }


        /// <summary>
        /// 重置视图区域
        /// </summary>
        public void ResetExtent(Rectangle view)
        {
            _currentView = view;
            Extent ext = this.PixelToProj(this._currentView);
            this.ViewExtent = ext;
        }

        /// <summary>
        /// 重新设置范围的比例。比如一个图层只有一条横向的线，
        /// 当ZoomToLayer时，这个图层的范围的比例就不适合窗体的范围了
        /// 所以在这里重新设置一下
        /// </summary>
        /// <param name="ext"></param>
        public void ResetExtentRatio(IExtent ext)
        {
            if (ext == null || ext.IsEmpty) return;

            double h = this._control.Height;
            double w = this._control.Width;

            if (h == 0 || w == 0) return;

            double MapRatio = w / h;
            double ExtRatio = ext.Width / ext.Height;

            double x = ext.Center.X;
            double y = ext.Center.Y;

            if (MapRatio > ExtRatio)
            {
                ext.MinX = x - MapRatio * ext.Height / 2;
                ext.MaxX = x + MapRatio * ext.Height / 2;
            }
            else
            {
                ext.MinY = y - ext.Width / MapRatio / 2;
                ext.MaxY = y + ext.Width / MapRatio / 2;
            }

            return;
        }


        /// <summary>
        /// 重新设置位图大小，并重新绘制图层
        /// </summary>
        public void ResetBufferImage()
        {
            this._bufferImage = this.CreateBufferImage();
            this.InitializeBackBitmap();
        }


        /// <summary>
        /// 屏幕矩形转相对矩形
        /// </summary>
        /// <param name="rect"></param>
        /// <returns></returns>
        public Extent PixelToProj(Rectangle rect)
        {
            Point leftUp = new Point(rect.X, rect.Y);
            Point bottomRight = new Point(rect.X + rect.Width, rect.Y + rect.Height);

            Coordinate gisLeftUp = PixelToProj(leftUp);
            Coordinate gisBottomRight = PixelToProj(bottomRight);

            return new Extent(gisLeftUp.X, gisBottomRight.Y, gisBottomRight.X, gisLeftUp.Y);
        }

        public Rectangle ProjToPixel(Extent ext)
        {
            Coordinate gisLeftUp = new Coordinate(ext.MinX, ext.MaxY);
            Coordinate gisBottomRight = new Coordinate(ext.Width, ext.Height);

            Point LeftUp = ProjToPixel(gisLeftUp);
            Point BottomRight = ProjToPixel(gisBottomRight);

            return new Rectangle(LeftUp.X, LeftUp.Y, BottomRight.X - LeftUp.X, BottomRight.Y - LeftUp.Y);
        }

        /// <summary>
        /// 屏幕坐标转相对坐标
        /// </summary>
        /// <param name="pt"></param>
        /// <returns></returns>
        public Coordinate PixelToProj(Point pt)
        {
            if (this.ViewExtent == null) return new Coordinate(0, 0);

            double x = pt.X;
            double y = pt.Y;

            x = this._viewExtent.MinX + x * this._viewExtent.Width / this._width;
            y = this._viewExtent.MaxY - y * this._viewExtent.Height / this._height;

            return new Coordinate(x, y);
        }


        public Point ProjToPixel(Coordinate point)
        {
            if (this.ViewExtent == null) return new Point(0, 0);

            double x = point.X;
            double y = point.Y;

            x = (x - this._viewExtent.MinX) * this._width / this._viewExtent.Width + this._control.ClientRectangle.X;
            y = (this._viewExtent.MaxY - y) * this._height / this._viewExtent.Height + this._control.ClientRectangle.Y;

            return new Point((int)x, (int)y);

        }

        /// <summary>
        /// 获取所有图层所形成的范围
        /// </summary>
        /// <returns></returns>
        private IExtent GetLayersExtent()
        {
            if (this.Layers == null) return null;
            IExtent ext = new Extent();
            foreach (IMapLayer layer in Layers)
            {
                ext = ext.Union(layer.Extent) as Extent;
            }
            if (ext.IsEmpty)
            {
                ext = new Extent(-180, -90, 180, 90);
            }

            return ext;
        }


        public void ZoomToMaxExtent()
        {
            this.ViewExtent = Extent;
        }

        #endregion


        #region 图层事件

        /// <summary>
        /// 订阅图层事件
        /// </summary>
        private void HandleLayerEvents()
        {
            Layers.LayerAdded += new EventHandler<LayerEventArgs>(LayerCollection_LayerAdded);
            Layers.LayerRemoved += new EventHandler<LayerEventArgs>(LayerCollection_LayerRemoved);
            Layers.LayerVisibleChanged += new EventHandler(LayerCollection_LayerVisibleChanged);
            Layers.DatasetContentChanged += new EventHandler(LayerCollection_DatasetContentChanged);
            Layers.LayerContentChanged += new EventHandler(LayerCollection_LayerContentChanged);
        }



        /// <summary>
        /// 移除图层事件
        /// </summary>
        public void RemoveLayerEvents()
        {
            Layers.LayerAdded -= new EventHandler<LayerEventArgs>(LayerCollection_LayerAdded);
            Layers.LayerRemoved -= new EventHandler<LayerEventArgs>(LayerCollection_LayerRemoved);
            Layers.LayerVisibleChanged -= new EventHandler(LayerCollection_LayerVisibleChanged);
            Layers.DatasetContentChanged -= new EventHandler(LayerCollection_DatasetContentChanged);
            Layers.LayerContentChanged -= new EventHandler(LayerCollection_LayerContentChanged);
        }


        /// <summary>
        /// 处理图层添加方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void LayerCollection_LayerAdded(object sender, LayerEventArgs e)
        {
            if (e.Layer == null) return;

            if (Layers.Count == 0)
            {
                ViewExtent = e.Layer.Extent;
            }
            else
            {
                InitializeBackBitmap();
            }

            if (_control != null)
                _control.Invalidate();
        }

        /// <summary>
        /// 处理图层移除方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void LayerCollection_LayerRemoved(object sender, LayerEventArgs e)
        {
            InitializeBackBitmap();
            if (_control != null)
                _control.Invalidate();
        }

        /// <summary>
        /// 处理图层可见改变方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void LayerCollection_LayerVisibleChanged(object sender, EventArgs e)
        {
            InitializeBackBitmap();
            if (_control != null)
                _control.Invalidate();
        }

        /// <summary>
        /// 处理图层内图形改变方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void LayerCollection_DatasetContentChanged(object sender, EventArgs e)
        {
            InitializeBackBitmap();
            if (_control != null)
                _control.Invalidate();
        }

        /// <summary>
        /// 图层内容改变。如图层样式改变
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void LayerCollection_LayerContentChanged(object sender, EventArgs e)
        {
            InitializeBackBitmap();
            if (_control != null)
                _control.Invalidate();
        }

        #endregion



        #region IMap成员方法


        public void AddLayer(IMapLayer layer)
        { 
        }


        public void AddVectorLayer(IMapVectorLayer vectorLayer)
        { 
        }


        public void RemoveLayer(int index)
        { 
        }


        public IMapLayer GetLayer(int index)
        {
            return null;
        }


        #endregion



        #region 选择


        public void Select(IExtent Region)
        {
            foreach (IMapLayer layer in _layers)
            {
                layer.Select(Region);
            }
        }

        public void Select(IExtent Region, SelectionMode Mode)
        {
            foreach (IMapLayer layer in _layers)
            {
                layer.Select(Region, Mode);
            }
        }


        public void ClearSelected()
        {
            foreach (IMapLayer layer in _layers)
            {
                layer.ClearSelected();
            }
            InitializeBackBitmap();
        }


        public void RemoveSelected()
        {
            foreach (IMapLayer layer in _layers)
            {
                layer.RemoveSelected();
            }
            InitializeBackBitmap();                                   
        }

        #endregion


    }


}
